package cn.epsilon3.handler;

import cn.epsilon3.annotation.E3Config;
import cn.epsilon3.constant.ClassTypeEnum;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.util.Arrays;

/**
 * @description E3 spring后置处理器
 * @author: epsilon3
 * @date: 2023/12/1 10:26
 */

@Component
public class E3BeanPostHandler implements BeanPostProcessor {

    private static final Log log = LogFactory.get();

    @Resource
    private Environment environment;

    /**
     * bean 初始化之前处理
     *
     * @param bean bean
     * @param beanName beanName
     * @return
     * @throws BeansException
     */
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        parseE3Config(bean);
        return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
    }


    /**
     * 解析@E3Config
     * 基本属性赋值
     *
     * @param bean bean对象
     */
    private void parseE3Config(Object bean) {
        boolean annotationPresentConfigurationProperties = bean.getClass().isAnnotationPresent(ConfigurationProperties.class);
        if (annotationPresentConfigurationProperties) {
                ConfigurationProperties configurationProperties = bean.getClass().getAnnotation(ConfigurationProperties.class);
                String prefix = configurationProperties.prefix();
                Field[] declaredFields = bean.getClass().getDeclaredFields();
                for (Field declaredField : declaredFields) {
                    boolean annotationPresent = declaredField.isAnnotationPresent(E3Config.class);
                    if (annotationPresent) {
                        declaredField.setAccessible(true);
                        E3Config e3Config = declaredField.getAnnotation(E3Config.class);
                        String suffixName = e3Config.suffixName();
                        String path = prefix + "." + suffixName;
                        String property = environment.getProperty(path);
                        ClassTypeEnum classTypeEnum = e3Config.type();
                        Class<?> type = classTypeEnum.getType();
                        Object pathValue = environment.getProperty(path, type);
                        String defaultValue = e3Config.defaultValue();
                        Object value = null;
                        if (ObjectUtil.isNull(pathValue)) {
                            if (StrUtil.isNotBlank(defaultValue)) {
                                switch (classTypeEnum) {
                                    case INTEGER:
                                        value = Integer.parseInt(defaultValue);
                                        break;
                                    case LONG:
                                        value = Long.parseLong(defaultValue);
                                        break;
                                    case DOUBLE:
                                        value = Double.parseDouble(defaultValue);
                                        break;
                                    case FLOAT:
                                        value = Float.parseFloat(defaultValue);
                                        break;
                                    case BOOLEAN:
                                        value = Boolean.parseBoolean(defaultValue);
                                        break;
                                    case LIST:
                                        value = Arrays.asList(defaultValue.split(","));
                                        break;
                                    default:
                                        value = defaultValue;
                                }
                                try {
                                    declaredField.set(bean, value);
                                } catch (IllegalAccessException e) {
                                    throw new RuntimeException(e);
                                }
                            }
                        }
                    }
                }
        }
    }
}
